package zhou.chs.p4_1;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;

public class MainActivity extends AppCompatActivity  implements AdapterView.OnItemClickListener,View.OnClickListener{
    //定义控件
    ListView lv;                      //列表显示蓝牙MAC地址
    TextView tv1;                      //显示接收数据
    TextView tv2;                      //显示状态;
    EditText et;
    Button btConnect, btClear, btSave,btCRC,btSend;     //按键
    Spinner sel1,sel2;                            //HEX、TEXT选择
    //变量定义
    private BluetoothAdapter btAdapter;         //蓝牙适配器
    private BluetoothDevice btDevice;           //蓝牙设备
    private Set<BluetoothDevice> pairedBts;     //配对蓝牙设备集合
    private BluetoothSocket btSocket = null;    //蓝牙socket
    private Handler myhandler;                  //信息通道
    private LinkThread mlink;               //自定义连接线程
    private ComThread mcom;                 //自定义数据通信线程
    UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    public byte tbuf[] = new byte[100];        //发送缓冲区
    public byte rbuf[] = new byte[512];        //接收缓冲区
    private boolean isConnect;   //已连接状态
    String strbuf="";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv1 = (TextView) findViewById(R.id.idtv1);
        tv2 = (TextView) findViewById(R.id.idtv2);
        et = (EditText) findViewById(R.id.idet);
        tv1.setMovementMethod(ScrollingMovementMethod.getInstance());  //设定文本可滚动
        btConnect = (Button) findViewById(R.id.idConnect);
        btClear = (Button) findViewById(R.id.idClear);
        btSave = (Button) findViewById(R.id.idSave);
        btCRC = (Button) findViewById(R.id.idCRC);
        btSend = (Button) findViewById(R.id.idSend);
        btConnect.setOnClickListener(this);
        btClear.setOnClickListener(this);
        btSave.setOnClickListener(this);
        btCRC.setOnClickListener(this);
        btSend.setOnClickListener(this);
        sel1 = (Spinner) findViewById(R.id.idS1);
        sel2 = (Spinner) findViewById(R.id.idS2);
        lv = (ListView) findViewById(R.id.idLv);
        lv.setOnItemClickListener(this);
        myhandler = new MyHandler();        //实例化Handler，用于进程间的通信
        btSend.setEnabled(false);
        btAdapter = BluetoothAdapter.getDefaultAdapter();   //蓝牙适配器
    }
    //响应按键单击事件
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.idConnect:        //配对蓝牙按钮
                pairedBts = btAdapter.getBondedDevices();   //获得已配对蓝牙设备集合
                ArrayList bt_list = new ArrayList();
                lv.setEnabled(true);
                if (!btAdapter.isEnabled()) {           //当前蓝牙适配器不可用
                    Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                    startActivityForResult(turnOn, 0);    //调用打开蓝牙适配器程序
                    tv2.setText("打开蓝牙模块");
                } else {
                    tv2.setText("蓝牙模块已打开");
                }
                for(BluetoothDevice bt : pairedBts){ //已配对蓝牙设备集合转为列表
                    bt_list.add(bt.getName() + "\n" + bt.getAddress());
                }               //列表放入适配器
                final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, bt_list);
                lv.setAdapter(adapter);  //通过适配器在ListView上显示配对蓝牙设备列表
                tv2.setText("选择蓝牙设备");
                break;
            case R.id.idClear:           //清空按钮
                strbuf="";
                tv1.setText("");
                break;
            case R.id.idSave:          //保存按钮
                File file = new File(this.getExternalFilesDir
                        (Environment.DIRECTORY_DOCUMENTS),"mydata.txt");
                try {
                    FileWriter fw = new FileWriter(file);
                    fw.write(strbuf);
                    fw.close();
                } catch (Exception e) {
                }
                break;
            case R.id.idCRC:          //CRC按钮
                if(sel2.getSelectedItemPosition()==0) { //HEX模式
                    String s=et.getText().toString();
                    et.setText(crc16(s));
                }
                break;
            case R.id.idSend:          //发送按钮
                String strcmd;
                byte[] tbuf;
                int n;
                if(sel2.getSelectedItemPosition()==0) { //HEX模式
                    strcmd=et.getText().toString().replaceAll(" ", "");
                    n=strcmd.length();
                    tbuf = new byte[n / 2];  // 待发送数据
                    for (int i = 0; i < n; i += 2) {
                        // 两位一组，表示一个字节,把这样表示的16进制字符串，还原成一个字节
                        tbuf[i / 2] = (byte) ((Character.digit(strcmd.charAt(i), 16) << 4) + Character.digit(strcmd.charAt(i + 1), 16));
                    }
                }else{                                  //TEXT模式
                    strcmd=et.getText().toString();
                    n=strcmd.length();
                    tbuf = new byte[n];  // 待发送数据
                    tbuf = strcmd.getBytes();
                }
                mcom.write(tbuf);      //发送数据
                break;
        }
    }
    //响应列表单击选项事件
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        TextView txv = (TextView) view;  //获取选中项文本
        String s = txv.getText().toString();
        String[] addr = s.split("\n");   //抽取MAC地址
        try {
            btDevice = btAdapter.getRemoteDevice(addr[1]);  //通过MAC地址获得蓝牙设备
            lv.setEnabled(false);
        } catch (Exception e) {
            tv2.setText("获取设备失败");
        }
        mlink = new LinkThread(btDevice);  //在蓝牙设备连接线程中加载蓝牙设备
        mlink.start();   //启动连接蓝牙设备线程
    }
    //连接蓝牙装置
    private class LinkThread extends Thread {
        public LinkThread(BluetoothDevice mDevice) {
            btSocket = null;
            try {
                btSocket = mDevice.createRfcommSocketToServiceRecord(uuid);  //定义Socket为蓝牙串口服务
            } catch (Exception e) {
                Message msg0 = myhandler.obtainMessage();
                msg0.what = 0;
                myhandler.sendMessage(msg0);  //通知主线程蓝牙设备未打开或不支持串口服务
            }
        }
        public final void run() {
            btAdapter.cancelDiscovery();
            try {
                btSocket.connect();       //建立Socket连接
                isConnect = true;
                mcom = new ComThread(btSocket);
                mcom.start();       //建立连接后启动建立数据通信线程
                Message msg1 = myhandler.obtainMessage();
                msg1.what = 1;
                myhandler.sendMessage(msg1);    //通知主线程可以开始通信
            } catch (IOException e1) {
                isConnect = false;
                Message msg2 = myhandler.obtainMessage();
                msg2.what = 2;
                myhandler.sendMessage(msg2);    //通知主线程无法建立Socket连接
                try {
                    btSocket.close();   //关闭蓝牙连接
                    btSocket = null;
                } catch (IOException e2) {

                }
            }
        }
    }
    //在主线程处理Handler传回来的message
    class MyHandler extends Handler {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    tv2.setText("蓝牙设备未打开或不支持串口服务！");
                    break;
                case 1:
                    tv2.setText("可以开始通信");
                    btSend.setEnabled(true);
                    break;
                case 2:
                    tv2.setText("无法建立Socket连接");
                    break;
                case 3:
                    tv2.setText("收到数据");
                    int n=Integer.parseInt(msg.obj.toString());
                    if(sel1.getSelectedItemPosition()==0) { //HEX模式
                        for(int i=0;i<n;i++) strbuf += String.format("%02X", rbuf[i]) + " ";
                    }else{
                        char[] buf = new char[n];
                        for(int i=0;i<n;i++) buf[i]=(char) rbuf[i];
                        strbuf += String.copyValueOf(buf);
                    }
                    tv1.setText(strbuf);
                    break;
                case 4:
                    tv2.setText("检查蓝牙设备，重新连接");
                    break;
            }
        }
    }
    //数据通信线程
    private class ComThread extends Thread {
        private final BluetoothSocket mSocket;
        private final InputStream mInStream;    //定义输入流
        private final OutputStream mOutStream;  //定义输出流

        public ComThread(BluetoothSocket socket) {   //socket连接
            mSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
            try {
                tmpIn = mSocket.getInputStream();      //Socket输入数据流
                tmpOut = mSocket.getOutputStream();    //Socket输出数据流
            } catch (IOException e) {
            }
            mInStream = tmpIn;
            mOutStream = tmpOut;
        }
        //阻塞线程接收数据
        public final void run() {
            byte[] buf = new byte[512];  // 接收数据临时缓冲区
            while (isConnect) {
                try {
                    int byt = mInStream.read(buf);
                    if(byt>0) {
                        for (int i = 0; i < byt; i++) rbuf[i] = buf[i];  // 收到数据后转移到待处理存储区
                        try {
                            sleep(100);     //延时100ms，等接收区数据处理完毕
                        } catch (InterruptedException e) {
                        }
                        int n = mInStream.read(buf);
                        for (int i = 0; i < n; i++) rbuf[byt+i] = buf[i];  // 收到数据后转移到待处理存储区
                        Message msg3 = myhandler.obtainMessage();
                        msg3.what = 3;
                        msg3.obj = byt+n;
                        myhandler.sendMessage(msg3); // 通知主线程接收到数据
                        try {
                            sleep(100);     //延时100ms，等接收区数据处理完毕
                        } catch (InterruptedException e) {
                        }
                    }
                } catch (NullPointerException e) {
                    isConnect = false;
                    Message msg4 = myhandler.obtainMessage();
                    msg4.what = 4;
                    myhandler.sendMessage(msg4);    //通知主线程蓝牙设备连接已断开
                    break;
                } catch (IOException e) {
                    break;
                }
            }
        }
        //发送字节数据
        public void write(byte[] bytes) {
            try {
                mOutStream.write(bytes);
            } catch (IOException e) {
            }
        }
        //关闭蓝牙连接
        public void cancel() {
            try {
                mSocket.close();
            } catch (IOException e) {
            }
        }
    }
    //CRC校验子程序
    public static StringBuffer crc16(String strtbuf) {
        strtbuf = strtbuf.replaceAll(" ", ""); //去掉字符串中的空格
        int n = strtbuf.length();
        String ad;
        int[] w=new int[n/2];
        for (int i = 0; i <n; i=i+2) {  //字符串转为16进制数据
            ad=strtbuf.substring(i,i+2);
            w[i/2]=Integer.parseInt(ad,16);
        }
        int[] data=w;
        int[] stem=new int[data.length+2];
        //CRC校验计算
        int a,b,c;
        a=0xFFFF;
        b=0xA001;
        for (int i = 0; i < data.length; i++) {
            a^=data[i];
            for (int j = 0; j < 8; j++) {
                c=(int)(a&0x01);
                a>>=1;
                if (c==1) {
                    a^=b;
                }
                System.arraycopy(data, 0, stem, 0, data.length);
                stem[stem.length-2]=(int)(a&0xFF);
                stem[stem.length-1]=(int)(a>>8);
            }
        }
        int[] z = stem;
        StringBuffer s = new StringBuffer();
        for (int j = 0; j < z.length; j++) {
            s.append(String.format("%02X", z[j]));
        }
        return s;  //返回带校验的字符串
    }
}
